import java.util.Arrays;

public class Matrix {
  /**
   * 通过矩阵返回行向量，直接返回，只为了代码可读性更强
   * 
   * @param m1
   * @return
   */
  public double[] getRowVector(double[] m) {
    return m;
  }

  /**
   * 通过输入的数组返回，这个数组对应的行向量的转置，即返回列向量
   * 
   * @param m1
   * @return
   */
  public double[][] getColVector(double[] m) {
    double[][] mTo = new double[1][1];
    mTo[0] = m;
    return matrixTranspose(mTo);
  }

  /**
   * 通过一个数组返回一个矩阵，直接返回，为了提高代码可读性
   * 
   * @param m
   * @return
   */
  public double[][] getMatrix(double[][] m) {
    return m;
  }


  /**
   * 返回输入矩阵的转置
   * 
   * @param m
   * @return
   */
  public double[][] matrixTranspose(double[][] m) {
    double[][] res = new double[m[0].length][m.length];
    for (int i = 0; i < m.length; i++) {
      for (int j = 0; j < m[0].length; j++) {
        res[j][i] = m[i][j];
      }
    }
    return res;
  }

  /**
   * 返回矩阵相加的结果， m1[m] + m2[m] = res[m]
   * 
   * @param m1
   * @param m2
   * @return
   */
  public double[] matrixAdd(double[] m1, double[] m2) {
    double[][] m1To = new double[1][1];
    m1To[0] = m1;
    double[][] m2To = new double[1][1];
    m2To[0] = m2;
    return matrixAdd(m1To, m2To)[0];
  }

  /**
   * 返回矩阵相加的结果，m1[m][n] * m2[m]n] = res[m][n]
   * 
   * @param m1
   * @param m2
   * @return
   */
  public double[][] matrixAdd(double[][] m1, double[][] m2) {
    if (m1.length != m2.length || m1[0].length != m2[0].length) {
      System.out.println("这两个矩阵不能相加，他们的维度不一样");
      return null;
    }
    double[][] res = new double[m1.length][m2[0].length];
    for (int i = 0; i < m1.length; i++) {
      for (int j = 0; j < m1[0].length; j++) {
        res[i][j] = m1[i][j] + m2[i][j];
      }
    }
    return res;
  }

  /**
   * 返回两个矩阵相乘的结果，结果也是一个矩阵。m1[m][n] * m2[n][t] = res[m][t]
   * 
   * @param m1
   * @param m2
   * @return
   */
  public double[][] matrixMultiply(double[][] m1, double[][] m2) {
    if (m1[0].length != m2.length) {
      System.out.println("矩阵不能相乘，因为不满足 m1[m][n] * m2[n][t] = res[m][t]");
      return null;
    }
    double[][] res = new double[m1.length][m2[0].length];
    for (int i = 0; i < m1[0].length; i++) {
      for (int j = 0; j < m2.length; j++) {
        double[] row = getMatrixRow(m1, i);
        double[] col = getMatrixCol(m2, j);
        res[i][j] = matrixInnerMultiply(row, col);
      }
    }
    return res;
  }

  /**
   * 返回行向量 * 列向量
   * 
   * @param m1
   * @param m2
   * @return
   */
  public double[][] matrixMultiply(double[] m1, double[][] m2) {
    double[][] m1To = new double[1][1];
    m1To[0] = m1;
    return matrixMultiply(m1To, m2);
  }


  /**
   * 返回单行矩阵，与单列矩阵的乘积，m1[m] * m2[m] = res
   * 
   * @param m1
   * @param m2
   * @return
   */
  public double matrixInnerMultiply(double[] m1, double[] m2) {
    double res = 0;
    for (int i = 0; i < m1.length; i++) {
      res += m1[i] * m2[i];
    }
    return res;
  }

  /**
   * 返回（num * 矩阵）的结果
   * 
   * @param num
   * @param m2
   * @return
   */
  public double[][] matrixMultiply(double num, double[][] m2) {
    double[][] res = new double[m2.length][m2[0].length];
    for (int i = 0; i < m2.length; i++) {
      for (int j = 0; j < m2[0].length; j++) {
        res[i][j] = num * m2[i][j];
      }
    }
    return res;
  }

  /**
   * 返回（矩阵 * num）的结果
   * 
   * @param m1
   * @param num
   * @return
   */
  public double[][] matrixMultiply(double[][] m1, double num) {
    return matrixMultiply(num, m1);
  }

  /**
   * 返回（num * 矩阵）的结果
   * 
   * @param num
   * @param m2
   * @return
   */
  public double[] matrixMultiply(double num, double[] m2) {
    double[][] m2To = new double[1][1];
    m2To[0] = m2;
    return matrixMultiply(num, m2To)[0];
  }

  /**
   * 返回(矩阵 * num)的结果
   * 
   * @param m1
   * @param num
   * @return
   */
  public double[] matrixMultiply(double[] m1, double num) {
    double[][] m1To = new double[0][0];
    m1To[0] = m1;
    return matrixMultiply(m1To, num)[0];
  }

  /**
   * 返回矩陣中指定的行
   * 
   * @param matrix 矩阵
   * @param row 要获取的行
   * @return
   */
  public double[] getMatrixRow(double[][] matrix, int row) {
    double[] res = new double[matrix[0].length];
    res = Arrays.copyOfRange(matrix[row], 0, matrix[row].length);
    return res;
  }

  /**
   * 返回矩阵中指定的列
   * 
   * @param matrix 矩阵
   * @param col 要获取的列
   * @return
   */
  public double[] getMatrixCol(double[][] matrix, int col) {
    double[] res = new double[matrix.length];
    for (int i = 0; i < matrix.length; i++) {
      res[i] = matrix[i][col];
    }
    return res;
  }

  public void matrixToString(double[][] matrix) {
    for (int i = 0; i < matrix.length; i++) {
      System.out.println(Arrays.toString(matrix[i]));
    }
  }

  public void matrixToString(double[] matrix) {
    double[][] target = new double[1][1];
    target[0] = matrix;
    matrixToString(target);
  }
}


